home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Macintosh Tracker 1.20 / source / Server⁄Tracker 4.0 / mac_audio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-23  |  38.7 KB  |  1,291 lines  |  [TEXT/KAHL]

  1. /* macintosh_audio.c */
  2.  
  3. /* All the stuff in this file was written by Thomas R. Lawrence. */
  4. /* See the "mac_readme" or "mac_programmer_info" files for more information */
  5. /* about the Macintosh port */
  6.  
  7. #include <Sound.h>
  8. #include <sane.h>
  9. #include "mac_event.h"
  10.  
  11. #include <math.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14.  
  15. #include "defs.h"
  16. #include "extern.h"
  17. #include "song.h"
  18. #include "channel.h"
  19.  
  20. #define CONSTRAIN(value,min,max) MAX(MIN(value,max),min)
  21.  
  22. #define MAXNUMBUFFERS (128)
  23. #define MAXBUFFERSIZE (8192)
  24. #define MinFreeMem (32768 + MAXBUFFERSIZE + 256)
  25.  
  26. /* comment this out to use C-code */
  27. #define USE_ASSEMBLY_CODE (1) /* 1 = yes, 0 = no */
  28.  
  29. typedef struct MyS
  30.     {
  31.         struct MyS*            Next; /* circular linked list embedded in a static array */
  32.         SndCommand            MySoundCommand;
  33.         SndCommand            MyCallbackCommand;
  34.         volatile short    InUseFlag; /* interrupt level flag; hence "volatile" */
  35.         ExtSoundHeader    Header;
  36.         char                        SampleArea[MAXBUFFERSIZE];
  37.     } MyStructure;
  38.  
  39. static pascal void        MyCallBack(SndChannel* Channel, SndCommand* Command);
  40.  
  41. extern Boolean                QuitPending;
  42.  
  43. static int                        mac_stereo;
  44. /* 256th of primary/secondary source for that side. */
  45. static int                        primary=256, secondary=0;
  46. extern short                    Loudness;
  47.  
  48. /* the following array is grouped as 16*256 2-byte words.    Bits 9..12 of the */
  49. /* index are the most significant bits of the fraction of the pointer for */
  50. /* anti-aliasing.    Bits 1..8 are the sample's value.    If Bit 0 of the address is */
  51. /* 0, then this is the partially weighted left hand side for the antialiasing */
  52. /* average.    Bit 0 == 1 is the right hand side.    The left hand side is */
  53. /* the fraction * sample.    The right hand side is 2s complement of fraction * sample */
  54. static char*                    AliasTable = NULL;
  55.  
  56. /* the following array is a 1024-byte array for converting samples overall loudness */
  57. /* with clipping instead of roll-over.    This is because each raw sample value */
  58. /* ranges from -128..127.    We convert this to unsigned for the table: 0..255 */
  59. /* There are 4 channels, so the maximum is 4*255 == 1020.    Thus, we provide */
  60. /* 1024 (a nice round number) values.    When the table is constructed, the */
  61. /* values are constrained (i.e. clipped) so that rollover doesn't occur.    This */
  62. /* makes the sound a bit better when the volume is high enough to cause */
  63. /* rollover.    The maximum value of abs(FinalVolumeTablePrimary) is "primary" */
  64. /* and the max of abs(FinalVolumeTableSecondary) is "secondary".    See */
  65. /* "resample" for usage notes */
  66. static char*                    FinalVolumeTablePrimary = NULL;
  67. static char*                    FinalVolumeTableSecondary = NULL;
  68.  
  69. /* the following array is a 0..64*256 entry array for converting volume */
  70. /* (in the upper bits) and an 8-bit sample value into a new sample value. */
  71. /* an upper value of 64 represents no scaling. */
  72. /* You use this like this: */
  73. /* SubVolumeTable[<8-bit sample> + 256 * <6-bit volume level>] */
  74. static short*                 SubVolumeTable = NULL;
  75.  
  76. /* the following array is used for workspace */
  77. static long                        WorkspaceBytes = 0;
  78. static short*                    WorkspaceArray1 = NULL;
  79. static short*                    WorkspaceArray2 = NULL;
  80.  
  81. static SndChannel*        MySoundChannel; /* here's where it all happens, folks */
  82.  
  83. static MyStructure*        Buffers[MAXNUMBUFFERS];
  84. static int                        ActualNumBuffers;
  85. static MyStructure*        CurrentBuffer;
  86. static int                        buf_index;
  87.  
  88. short                                    Pausing = false;
  89.  
  90. /* this is dragged in from "mac_event" */
  91. extern short                    NumBits; /* what they want */
  92. static int                        ActualNumBits; /* what we're actually using */
  93.  
  94. /* the following defines have also been lifted from "audio.c" */
  95. extern int allocated;
  96. #define MAX_CHANNELS 8
  97. #define DO_NOTHING 0
  98. #define PLAY 1
  99. #define REPLAY 2
  100. extern struct audio_channel
  101.    {
  102.    struct sample_info *samp;
  103.    int mode;
  104.    unsigned long pointer;
  105.    unsigned long step;
  106.    int volume;
  107.    int pitch;
  108.    } chan[MAX_CHANNELS];
  109.  
  110. /* this is called from the event cycle which is called from the synthesizer via */
  111. /* the invocation of "may_getchar()".    When the program is playing */
  112. /* (Pausing == false), it sets Pausing to true, pauses the Macintosh sound */
  113. /* channel, and then spinwaits, calling may_getchar to provide processing time */
  114. /* to other programs.    When the event to unpause is received, this program is */
  115. /* invoked again (the first activation record is still present--recursive */
  116. /* invocation).    The second call unpauses the sound channel and clears the flag. */
  117. /* As the call stack is unrolled, control will be returned here.    Since the */
  118. /* Pausing flag is now clear, this routine will exit and things will carry */
  119. /* on normaly.    FLAW:    pauseCmd does not seem to have an effect.    The buffered */
  120. /* sound will play out and sound will stop only when all prepared buffers */
  121. /* have been played.    I don't know how to fix this; it seems to be a problem in */
  122. /* the Macintosh OS, not in this program. */
  123. void                TogglePause(void)
  124.     {
  125.         SndCommand            MyCommand;
  126.  
  127.         if (Pausing)
  128.             {
  129.                 Pausing = false;
  130.                 MyCommand.cmd = resumeCmd;
  131.                 MyCommand.param1 = 0;
  132.                 MyCommand.param2 = 0;
  133.                 SndDoImmediate(MySoundChannel,&MyCommand);
  134.             }
  135.          else
  136.             {
  137.                 Pausing = true;
  138.                 MyCommand.cmd = pauseCmd;
  139.                 MyCommand.param1 = 0;
  140.                 MyCommand.param2 = 0;
  141.                 SndDoImmediate(MySoundChannel,&MyCommand);
  142.                 while (Pausing && !QuitPending)
  143.                     {
  144.                         may_getchar();
  145.                     }
  146.             }
  147.     }
  148.  
  149.  
  150. /* adjust the stereo mixing.    Percent is 0..100; each channel takes on a value */
  151. /* in 0..256, providing 8-bits of scaling.    At full volume for a channel, */
  152. /* 256 represents a shift left by 8.    Thus, a shift right by 8 is the necessary */
  153. /* correction after scaling.    "primary" is for the main channel and "secondary" */
  154. /* is for the other channel.    They do not correspond strictly to left and right. */
  155. void            set_mix(int percent)
  156.     {
  157.         percent *= (256/2);
  158.         percent /= 100;
  159.         secondary = percent;
  160.         primary = 256 - percent;
  161.     }
  162.  
  163.  
  164. /* recalibrate the volume lookup table using a new value.    This is done on */
  165. /* the fly as volume levels are adjusted. */
  166. void            ResetVolumeTable(void)
  167.     {
  168.         short                Scan;
  169.         short                Intermediate;
  170.         short                Radius;
  171.  
  172.         if (FinalVolumeTablePrimary == NULL)
  173.             {
  174.                 FinalVolumeTablePrimary = (char*)NewPtr(1024 * sizeof(char));
  175.                 if (FinalVolumeTablePrimary == NULL)
  176.                     {
  177.                         perror("Not enough memory to play song.");
  178.                         end_all("");
  179.                     }
  180.             }
  181.         /* primary ranges between 0..255; abs(sample) ranges between 0..127. */
  182.         /* so we divide by 2 and subtract 1 just in case -128 gets in.    The radius */
  183.         /* is the maximum value we'll allow the sample to be.    Anything above */
  184.         /* is clipped.    Primary Radius + Secondary Radius == 127 (barring rounding */
  185.         /* errors.)    Thus we clip just before arithmetic rollover occurs. */
  186.         Radius = (primary / 2) - 1;
  187.         if (Radius < 0)
  188.             {
  189.                 Radius = 0;
  190.             }
  191.         for (Scan = -512; Scan <= 511; Scan += 1)
  192.             {
  193.                 Intermediate = (Scan * Loudness * primary) / (64 * 256);
  194.                 if (Intermediate > Radius)
  195.                     {
  196.                         Intermediate = Radius;
  197.                     }
  198.                 if (Intermediate < -Radius)
  199.                     {
  200.                         Intermediate = -Radius;
  201.                     }
  202.                 FinalVolumeTablePrimary[Scan & 0x03ff] = Intermediate;
  203.             }
  204.  
  205.         if (FinalVolumeTableSecondary == NULL)
  206.             {
  207.                 FinalVolumeTableSecondary = (char*)NewPtr(1024 * sizeof(char));
  208.                 if (FinalVolumeTableSecondary == NULL)
  209.                     {
  210.                         perror("Not enough memory to play song.");
  211.                         end_all("");
  212.                     }
  213.             }
  214.         Radius = (secondary / 2) - 1;
  215.         if (Radius < 0)
  216.             {
  217.                 Radius = 0;
  218.             }
  219.         for (Scan = -512; Scan <= 511; Scan += 1)
  220.             {
  221.                 Intermediate = (Scan * Loudness * secondary) / (64 * 256);
  222.                 if (Intermediate > Radius)
  223.                     {
  224.                         Intermediate = Radius;
  225.                     }
  226.                 if (Intermediate < -Radius)
  227.                     {
  228.                         Intermediate = -Radius;
  229.                     }
  230.                 FinalVolumeTableSecondary[Scan & 0x03ff] = Intermediate;
  231.             }
  232.     }
  233.  
  234.  
  235. int                open_audio(int SampleRate, int StereoFlag)
  236.     {
  237.         OSErr                            Error;
  238.         short                            Scan;
  239.         short                            Index;
  240.         SndCommand                Cmd;
  241.         long double                Fred;
  242.         unsigned long            FixedSampleRate;
  243.         MyStructure*            LastBuffer;
  244.  
  245.         if ((NumBits != 8) && (NumBits != 16))
  246.             {
  247.                 NumBits = 8;
  248.             }
  249.         ActualNumBits = NumBits;
  250.         FixedSampleRate = ((long)SampleRate) << 16;
  251.         if (FixedSampleRate == 0)
  252.             {
  253.                 FixedSampleRate = rate22khz;
  254.             }
  255.  
  256.         if (AliasTable == NULL)
  257.             {
  258.                 AliasTable = (char*)NewPtr(16*256*2);
  259.                 if (AliasTable == NULL)
  260.                     {
  261.                         perror("Not enough memory to play song.");
  262.                         end_all("");
  263.                     }
  264.                 for (Scan = 0; Scan <= 15; Scan += 1)
  265.                     {
  266.                         for (Index = -128; Index <= 127; Index += 1)
  267.                             {
  268.                                 short                TableIndex;
  269.  
  270.                                 /* we precompute the antialiasing multiplication table here. */
  271.                                 /* Scan == the high 4 bits of the fraction of the pointer which */
  272.                                 /* is accessing the sampled sound.    Thus 0 IS a sample point, */
  273.                                 /* 1 is just to the right of a sample point, and 15 is just to */
  274.                                 /* the left of a sample point.    As we approach the right, the */
  275.                                 /* value increases, so the right weight is just Scan.    As we */
  276.                                 /* approach the left, the weight increases, but Scan decreases */
  277.                                 /* so the value is 16-Scan.    When Scan == 0, the weight of the */
  278.                                 /* right is 0, and the full left value is used.    This is because */
  279.                                 /* at this point, the left sample is being pointed directly to */
  280.                                 /* so it's actual value should be returned. */
  281.                                 TableIndex = ((Scan << 8) | (Index & 0x00ff)) << 1;
  282.                                 AliasTable[TableIndex + 0] = ((16 - Scan) * Index) / 16;
  283.                                 AliasTable[TableIndex + 1] = (Scan * Index) / 16;
  284.                             }
  285.                     }
  286.             }
  287.  
  288.         ResetVolumeTable();
  289.  
  290.         if (SubVolumeTable == NULL)
  291.             {
  292.                 SubVolumeTable = (short*)NewPtr((MAX_VOLUME-MIN_VOLUME+1)*256*sizeof(short));
  293.                 if (SubVolumeTable == NULL)
  294.                     {
  295.                         perror("Not enough memory to play song.");
  296.                         end_all("");
  297.                     }
  298.                 for (Scan = 0; Scan <= MAX_VOLUME - MIN_VOLUME; Scan += 1)
  299.                     {
  300.                         for (Index = -128; Index <= 127; Index += 1)
  301.                             {
  302.                                 SubVolumeTable[(Scan << 8) | (Index & 0x00ff)]
  303.                                     = ((Scan + MIN_VOLUME) * Index + ((MAX_VOLUME - MIN_VOLUME)/2))
  304.                                     / (MAX_VOLUME - MIN_VOLUME);
  305.                                 /* normally, that would be MAX_VOLUME - MIN_VOLUME + 1, but */
  306.                                 /* we want to be 0..1 instead of 0..0.99999 because MAX_VOLUME */
  307.                                 /* should not scale the volume at all. */
  308.                             }
  309.                     }
  310.             }
  311.  
  312.         mac_stereo = StereoFlag;
  313.  
  314.         Error = SndNewChannel(&MySoundChannel,
  315.             sampledSynth, /* what synthesizer to use */
  316.             (StereoFlag * initStereo)
  317.                 | initNoInterp, /* we do oversampling ourselves */
  318.             (void*)MyCallBack /* == our buffer unmarking callback routine */);
  319.         if (Error != noErr)
  320.             {
  321.                 perror("unable to open sound channel");
  322.                 end_all("");
  323.             }
  324.         Cmd.cmd = ampCmd;
  325.         Cmd.param1 = 255;
  326.         Cmd.param2 = 0;
  327.         Error = SndDoImmediate(MySoundChannel,&Cmd);
  328.         if (Error != noErr)
  329.             {
  330.                 perror("unable to initialize sound channel");
  331.             }
  332.  
  333.         /* create an initial workspace */
  334.         WorkspaceBytes = (1500 * sizeof(short) + 3) & ~3L; /* should be plenty */
  335.         WorkspaceArray1 = (void*)NewPtr(WorkspaceBytes);
  336.         WorkspaceArray2 = (void*)NewPtr(WorkspaceBytes);
  337.         if ((WorkspaceArray1 == NULL) || (WorkspaceArray2 == NULL))
  338.             {
  339.                 FatalError(FatalErrorOutOfMemory);
  340.                 perror("No memory to allocate workspace.");
  341.                 end_all("");
  342.             }
  343.  
  344.         /* we now try to make as many buffers as we have memory for, so we can */
  345.         /* precompute the composite samples to be played as far ahead as we can */
  346.         /* so that momentary losses of control don't make the sound skip.    We */
  347.         /* need at least 3 buffers, for double buffering and to make our full */
  348.         /* usage check work.    (We check to see if all buffers are waiting to be played */
  349.         /* and not empty by counting the number of ones with a marked "InUseFlag" */
  350.         /* However, one buffer (the one under construction) will always be NOT */
  351.         /* marked.    If we settle for 2 buffers, then when we account for the buffer */
  352.         /* we are constructing, it will always look like all buffers are in use */
  353.         /* until all have stopped.    The sound will skip, so we might as well not */
  354.         /* play it at all.    Hence the limit of 3 buffers.) */
  355.         Scan = 0;
  356.         do
  357.             {
  358.                 MyStructure*            Temp;
  359.                 long                            FreeMemory;
  360.  
  361.                 FreeMemory = FreeMem();
  362.                 if (FreeMemory < MinFreeMem)
  363.                     {
  364.                         if (Scan < 3)
  365.                             {
  366.                                 perror("Not enough memory to play song!");
  367.                                 FatalError(FatalErrorOutOfMemory);
  368.                                 FatalError(FatalErrorOutOfMemory);
  369.                                 end_all("");
  370.                             }
  371.                          else
  372.                             {
  373.                                 goto StopMakingBuffers;
  374.                             }
  375.                     }
  376.                 Buffers[Scan] = (void*)NewPtr(sizeof(MyStructure));
  377.                 Buffers[Scan]->InUseFlag = 0;
  378.                 Buffers[Scan]->Header.samplePtr = &(Buffers[Scan]->SampleArea[0]);
  379.                 if (mac_stereo)
  380.                     {
  381.                         Buffers[Scan]->Header.sampleSize = ActualNumBits;
  382.                         Buffers[Scan]->Header.numChannels = 2;
  383.                     }
  384.                  else
  385.                     {
  386.                         Buffers[Scan]->Header.sampleSize = ActualNumBits;
  387.                         Buffers[Scan]->Header.numChannels = 1;
  388.                     }
  389.                 Buffers[Scan]->Header.sampleRate = FixedSampleRate;
  390.                 Buffers[Scan]->Header.loopStart = 0;
  391.                 Buffers[Scan]->Header.loopEnd = 0;
  392.                 Buffers[Scan]->Header.encode = extSH;
  393.                 Buffers[Scan]->Header.baseFrequency = 64;
  394.                 Buffers[Scan]->Header.markerChunk = NULL;
  395.                 Buffers[Scan]->Header.futureUse1 = 0;
  396.                 Buffers[Scan]->Header.futureUse2 = 0;
  397.                 Buffers[Scan]->Header.futureUse3 = 0;
  398.                 Buffers[Scan]->Header.futureUse4 = 0;
  399.                 Fred = SampleRate;
  400.                 x96tox80(&Fred,&(Buffers[Scan]->Header.AIFFSampleRate));
  401.                 Scan += 1;
  402.             } while (Scan < MAXNUMBUFFERS);
  403.      StopMakingBuffers:
  404.         ActualNumBuffers = Scan;
  405.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  406.             {
  407.                 /* now we establish the circular linked list so that we can */
  408.                 /* easily find out what the "next" buffer to use is */
  409.                 Buffers[Scan]->Next = Buffers[(Scan + 1) % ActualNumBuffers];
  410.             }
  411.         CurrentBuffer = Buffers[0];
  412.         buf_index = 0;
  413.  
  414.         return FixedSampleRate >> 16;
  415.     }
  416.  
  417.  
  418. /* this evaluates to see if all but the current buffer have been filled */
  419. /* and are waiting to be played.    If they have, then we can take a break in */
  420. /* the event loop since there won't be any work to do for a while. */
  421. static int        is_channel_full(void)
  422.     {
  423.         int                    Scan;
  424.         int                    Count;
  425.  
  426.         Count = 0;
  427.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  428.             {
  429.                 if (Buffers[Scan]->InUseFlag)
  430.                     {
  431.                         Count += 1;
  432.                     }
  433.             }
  434.         if (Count >= ActualNumBuffers - 1)
  435.             {
  436.                 return TRUE;
  437.             }
  438.          else
  439.              {
  440.                  return FALSE;
  441.              }
  442.     }
  443.  
  444.  
  445. /* here we check to see if all the buffers have played out.    This is done */
  446. /* at the end so that we don't close the channel too early and cut off the */
  447. /* end of the song. */
  448. static int        is_channel_empty(void)
  449.     {
  450.         int                    Scan;
  451.  
  452.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  453.             {
  454.                 if (Buffers[Scan]->InUseFlag)
  455.                     {
  456.                         return FALSE; /* nope, buffers are still in use */
  457.                     }
  458.             }
  459.         return TRUE;
  460.     }
  461.  
  462.  
  463. /* this counts the number of buffers waiting to be played.    The event loop uses */
  464. /* this to get an idea of how long it can sit around before worrying about */
  465. /* filling some more buffers. */
  466. short                NumberPendingBlocks(void)
  467.     {
  468.         int                    Scan;
  469.         int                    Count;
  470.  
  471.         Count = 0;
  472.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  473.             {
  474.                 if (Buffers[Scan]->InUseFlag)
  475.                     {
  476.                         Count += 1;
  477.                     }
  478.             }
  479.         return Count;
  480.     }
  481.  
  482.  
  483. /* queues the data to be played by the sound manager. */
  484. void            actually_flush_buffer(void)
  485.     {
  486.         OSErr                    Error;
  487.  
  488.         while (CurrentBuffer->Next->InUseFlag)
  489.             {
  490.                 /* since the list is a circular list, the next element is the "oldest" */
  491.                 /* element.    If it is full, then all the others are too, so we just wait. */
  492.                 /* if all the buffers have been filled, then we'll just spinwait */
  493.                 /* here for 0.25 of a second waiting for one to play out.    This could */
  494.                 /* be a problem.    If the number of buffers is small, then they might */
  495.                 /* appear to be full, but they could still play out in less than 0.25 */
  496.                 /* of a second.    See also "may_getchar" where a similar thing is done. */
  497.                 WaitForEvent(15);
  498.             }
  499.  
  500.      TryAgainPoint1:
  501.         CurrentBuffer->InUseFlag = 1;
  502.         CurrentBuffer->MySoundCommand.cmd = bufferCmd;
  503.         CurrentBuffer->MySoundCommand.param1 = 0;
  504.         CurrentBuffer->MySoundCommand.param2 = (long)&(CurrentBuffer->Header);
  505.         if (mac_stereo)
  506.             {
  507.                 /* stereo sample frames have 2 "samples" in them, so the index */
  508.                 /* into the buffer is twice the number of frames. */
  509.                 CurrentBuffer->Header.numFrames = buf_index / (2 * (ActualNumBits / 8));
  510.             }
  511.          else
  512.             {
  513.                 CurrentBuffer->Header.numFrames = buf_index / (1 * (ActualNumBits / 8));
  514.             }
  515.         Error = SndDoCommand(MySoundChannel,&(CurrentBuffer->MySoundCommand),1);
  516.         if (queueFull == Error)
  517.             {
  518.                 WaitForEvent(2);
  519.                 goto TryAgainPoint1;
  520.             }
  521.  
  522.         /* the callback is an interrupt level thing that clears a buffer so */
  523.         /* we can use it again. */
  524.      TryAgainPoint2:
  525.         CurrentBuffer->MyCallbackCommand.cmd = callBackCmd;
  526.         CurrentBuffer->MyCallbackCommand.param2 = (long)&(CurrentBuffer->InUseFlag);
  527.         Error = SndDoCommand(MySoundChannel,&(CurrentBuffer->MyCallbackCommand),1);
  528.         if (queueFull == Error)
  529.             {
  530.                 WaitForEvent(2);
  531.                 goto TryAgainPoint2;
  532.             }
  533.  
  534.         buf_index = 0;
  535.         CurrentBuffer = CurrentBuffer->Next;
  536.     }
  537.  
  538.  
  539. /* this function is not actually used */
  540. void            output_samples(int left, int right)
  541.     {
  542.         /* in the normal tracker, this is called EVERY TIME a sample frame is */
  543.         /* output.    It normally results in a call to flush_buffer.    Since */
  544.         /* THINK C won't inline functions, this was way to slow, so I dispensed with it */
  545.     }
  546.  
  547.  
  548. /* this flushes the buffer IF another cycle would overflow it.    Since the number */
  549. /* of bytes added to the buffer is SamplingRate / Speed, at high sampling rates */
  550. /* or ridiculously low speeds, larger than the buffer size could be created in */
  551. /* just one call to "resample."    This would be BAD.    Therefore "resample" checks */
  552. /* for this and returns a fatal error if it would happen. */
  553. void            my_flush_buffer(int BytesGenerated)
  554.     {
  555.         if (buf_index + BytesGenerated >= MAXBUFFERSIZE - 1)
  556.             actually_flush_buffer();
  557.     }
  558.  
  559.  
  560. /* waiting for all samples to play and then closing sound channel & disposing buffers */
  561. void            close_audio(void)
  562.     {
  563.         int                        Scan;
  564.         EventRecord        StupidEvent;
  565.  
  566.         if (buf_index != 0)
  567.             {
  568.                 /* make sure that last 1/8 of a second worth of song gets played. */
  569.                 actually_flush_buffer();
  570.             }
  571.  
  572.         /* wait for all buffers to play out */
  573.         /* if we receive a quit event, we just go away */
  574.         /* but for end of song, we wait for the buffers to play out */
  575.         /* SndDisposeChannel does this, but we want to be friendly to other */
  576.         /* processes by calling WaitNextEvent(), so we do it ourselves. */
  577.         while (!QuitPending && !is_channel_empty())
  578.             {
  579.                 WaitForEvent(60);
  580.             }
  581.  
  582.         /* close macintosh sound channel, cancel any callbacks */
  583. #if 0
  584.         /* I used to be using this quietCmd which, according to the great Inside */
  585.         /* Macintosh VI, should stop all processing on the channel.    Unfortunately, */
  586.         /* when I perform the call, the channel promptly becomes useless and the */
  587.         /* system hangs in the SndDisposeChannel routine waiting for some event */
  588.         /* that'll never happen (I have no idea what, but MacsBug clearly shows the */
  589.         /* infinite loop in system code). */
  590.         if (QuitPending)
  591.             {
  592.                 SndCommand        Cmd;
  593.  
  594.                 Cmd.cmd = quietCmd;
  595.                 Cmd.param1 = 0;
  596.                 Cmd.param2 = 0;
  597.                 SndDoImmediate(MySoundChannel,&Cmd);
  598.             }
  599. #endif
  600.         /* if we are supposed to quit right away, then we send 1 as the second */
  601.         /* parameter to do it right away, otherwise it'll wait for everything to */
  602.         /* play out before closing the channel */
  603.         SndDisposeChannel(MySoundChannel,QuitPending);
  604.  
  605.         /* release memory allocated for buffers */
  606.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  607.             {
  608.                 /* this isn't really necessary unless you play more than one song */
  609.                 /* at a time and the buffer is flushed each time. */
  610.                 DisposPtr((void*)Buffers[Scan]);
  611.             }
  612.     }
  613.  
  614.  
  615. /* what is this for? */
  616. void            set_synchro(int s)
  617.     {
  618.     }
  619.  
  620. /* another mystery function */
  621. int             update_frequency(void)
  622.     {
  623.         return 0;
  624.     }
  625.  
  626. void            discard_buffer(void)
  627.     {
  628.     }
  629.  
  630.  
  631. #if __option(profile)
  632. #define Profiling
  633. #endif
  634.  
  635. #pragma options(!profile)
  636.  
  637. /* asynchronous callback routine which marks buffers as now unused */
  638. /* It would be very bad to profile this since profiling tampers with the */
  639. /* stack invocation and uses A5 global variables!    (believe me, I've tried) */
  640. static pascal void        MyCallBack(SndChannel* Channel, SndCommand* Command)
  641.     {
  642.         *(short*)(Command->param2) = 0;
  643.     }
  644.  
  645. #ifdef Profiling
  646. #pragma options(profile)
  647. #endif
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656. /* stuff removed from "audio.c" */
  657.  
  658.  
  659. /* prototypes for my single channel resamplers have been added */
  660. void        SampleAntiAliased8(struct audio_channel* ch, short* Buffer, short Count);
  661. void        SampleAliased8(struct audio_channel* ch, short* Buffer, short Count);
  662. void        SampleAntiAliased16(struct audio_channel* ch, short* Buffer, short Count);
  663. void        SampleAliased16(struct audio_channel* ch, short* Buffer, short Count);
  664.  
  665.  
  666. /* a new "resample" function using my single channel resamplers has been added */
  667. void resample(int oversample, int number)
  668.     {
  669.         short                i;
  670.         short*            WA1Shadow;
  671.         short*            WA2Shadow;
  672.         short                BytesGenerated;
  673.  
  674.         /* flush the stuff to the buffer.    i.e. if we would overflow the */
  675.         /* buffer during this cycle, we flush it and get a new buffer. */
  676.         /* later on, checks are performed to make sure we won't overflow the buffer. */
  677.         /* the only time that would happen would be if BytesGenerated is bigger */
  678.         /* than the whole buffer. */
  679.         /* note that flush_buffer now takes a parameter */
  680.         if (mac_stereo)
  681.             {
  682.                 BytesGenerated = number * 2 * (ActualNumBits / 8);
  683.             }
  684.          else
  685.             {
  686.                 BytesGenerated = number * (ActualNumBits / 8);
  687.             }
  688.         my_flush_buffer(BytesGenerated);
  689.  
  690.         if (BytesGenerated + buf_index > MAXBUFFERSIZE)
  691.             {
  692.                 perror("Buffer size not set large enough");
  693.                 FatalError(FatalErrorInternalError);
  694.                 end_all("");
  695.             }
  696.  
  697.         /* we need a workspace where we construct the channels before scaling */
  698.         /* the final volume.    If we need a bigger one than originally anticipated */
  699.         /* we attempt to reallocate it. */
  700.      Reallocate:
  701.         if (WorkspaceBytes == 0)
  702.             {
  703.                 /* workspace always holds 16-bit values */
  704.                 WorkspaceBytes = (number * sizeof(short) + 3) & ~3L;
  705.                 WorkspaceArray1 = (void*)NewPtr(WorkspaceBytes);
  706.                 WorkspaceArray2 = (void*)NewPtr(WorkspaceBytes);
  707.                 if ((WorkspaceArray1 == NULL) || (WorkspaceArray2 == NULL))
  708.                     {
  709.                         perror("Ran out of memory playing song.");
  710.                         FatalError(FatalErrorOutOfMemory);
  711.                         end_all("");
  712.                     }
  713.             }
  714.          else
  715.             {
  716.                 if (WorkspaceBytes < ((number * sizeof(short) + 3) & ~3L))
  717.                     {
  718.                         DisposPtr((void*)WorkspaceArray1);
  719.                         DisposPtr((void*)WorkspaceArray2);
  720.                         WorkspaceBytes = 0;
  721.                         goto Reallocate;
  722.                     }
  723.             }
  724.  
  725.         /* first, erase the workspace, since SampleXXX adds to the workspace. */
  726.         WA1Shadow = WorkspaceArray1;
  727.         WA2Shadow = WorkspaceArray2;
  728.         for (i = WorkspaceBytes / sizeof(long) - 1; i >= 0; i -= 1)
  729.             {
  730.                 /* longs erase faster on 68030 */
  731.                 ((long*)WA1Shadow)[i] = 0;
  732.                 ((long*)WA2Shadow)[i] = 0;
  733.             }
  734.  
  735.         if (ActualNumBits == 8)
  736.             {
  737.                 char*            BufferAddress;
  738.  
  739.                 /* 8-bit sampling */
  740.  
  741.                 /* oversample == 1 is merely no antialiasing.    I didn't want to fiddle with */
  742.                 /* Espie's code, so I just use oversample instead of a new variable "antialiased" */
  743.                 if (oversample == 1)
  744.                     {
  745.                         /* WorkspaceArray1 is the left channel, WorkspaceArray2 is the right channel */
  746.                         SampleAliased8(&(chan[0]),WA1Shadow,number);
  747.                         SampleAliased8(&(chan[1]),WA2Shadow,number);
  748.                         SampleAliased8(&(chan[2]),WA2Shadow,number);
  749.                         SampleAliased8(&(chan[3]),WA1Shadow,number);
  750.                     }
  751.                  else
  752.                     {
  753.                         SampleAntiAliased8(&(chan[0]),WA1Shadow,number);
  754.                         SampleAntiAliased8(&(chan[1]),WA2Shadow,number);
  755.                         SampleAntiAliased8(&(chan[2]),WA2Shadow,number);
  756.                         SampleAntiAliased8(&(chan[3]),WA1Shadow,number);
  757.                     }
  758.                  /* notes about that stuff above:    workspace always holds 16-bit values, so */
  759.                  /* we don't have to fool with ActualNumBits to figure out how many bytes */
  760.                  /* the workspace should be. */
  761.  
  762.                 BufferAddress = &(CurrentBuffer->SampleArea[buf_index]);
  763.                 if (mac_stereo)
  764.                     {
  765.                         do
  766.                             {
  767.                                 /* Note how we add both the primary and secondary scaling tables. */
  768.                                 /* hence each table is independently clipped. */
  769.                                 /* left channel */
  770.                                 *(BufferAddress++) = FinalVolumeTablePrimary[(*WA1Shadow) & 0x03ff]
  771.                                     + FinalVolumeTableSecondary[(*WA2Shadow) & 0x03ff] + 128;
  772.                                 /* right channel */
  773.                                 *(BufferAddress++) = FinalVolumeTablePrimary[*(WA2Shadow++) & 0x03ff]
  774.                                     + FinalVolumeTableSecondary[*(WA1Shadow++) & 0x03ff] + 128;
  775.                                 number -= 1;
  776.                             } while (number > 0);
  777.                     }
  778.                  else
  779.                     {
  780.                         do
  781.                             {
  782.                                 /* for mono, we don't have any secondary sound coming in from */
  783.                                 /* the other channel. */
  784.                                 *(BufferAddress++) = FinalVolumeTablePrimary[(*(WA1Shadow++)
  785.                                     + *(WA2Shadow++)) & 0x03ff] + 128;
  786.                                 number -= 1;
  787.                             } while (number > 0);
  788.                     }
  789.             }
  790.          else
  791.             {
  792.                 short*            BufferAddress;
  793.  
  794.                 /* 16 bit sampling */
  795.  
  796.                 /* oversample == 1 is merely no antialiasing.    I didn't want to fiddle with */
  797.                 /* Espie's code, so I just use oversample instead of a new variable "antialiased" */
  798.                 if (oversample == 1)
  799.                     {
  800.                         /* WorkspaceArray1 is the left channel, WorkspaceArray2 is the right channel */
  801.                         SampleAliased16(&(chan[0]),WA1Shadow,number);
  802.                         SampleAliased16(&(chan[1]),WA2Shadow,number);
  803.                         SampleAliased16(&(chan[2]),WA2Shadow,number);
  804.                         SampleAliased16(&(chan[3]),WA1Shadow,number);
  805.                     }
  806.                  else
  807.                     {
  808.                         SampleAntiAliased16(&(chan[0]),WA1Shadow,number);
  809.                         SampleAntiAliased16(&(chan[1]),WA2Shadow,number);
  810.                         SampleAntiAliased16(&(chan[2]),WA2Shadow,number);
  811.                         SampleAntiAliased16(&(chan[3]),WA1Shadow,number);
  812.                     }
  813.                  /* notes about that stuff above:    workspace always holds 16-bit values, so */
  814.                  /* we don't have to fool with ActualNumBits to figure out how many bytes */
  815.                  /* the workspace should be. */
  816.  
  817.                 BufferAddress = (short*)&(CurrentBuffer->SampleArea[buf_index]);
  818.                 if (mac_stereo)
  819.                     {
  820.                         short                PrimaryV;
  821.                         short                SecondaryV;
  822.  
  823.                         PrimaryV = primary * Loudness;
  824.                         SecondaryV = secondary * Loudness;
  825.                         do
  826.                             {
  827.                                 /* left channel */
  828.                                 /* Primary + Secondary = 256; each buffer has -16384..16383 */
  829.                                 /* in it, Loudness could be 64, so we need to divide by 256*64 */
  830.                                 /* (16384; shift left by 14) */
  831.                                 *(BufferAddress++) = (short)((((*WA1Shadow) * PrimaryV)
  832.                                     + ((*WA2Shadow) * SecondaryV)) >> 14) /*+ (short)0x8000*/;
  833.                                 /* right channel */
  834.                                 *(BufferAddress++) = (short)((((*(WA2Shadow++)) * PrimaryV)
  835.                                     + ((*(WA1Shadow++)) * SecondaryV)) >> 14) /*+ (short)0x8000*/;
  836.                                 number -= 1;
  837.                             } while (number > 0);
  838.                     }
  839.                  else
  840.                     {
  841.                         short                LocalLoudness;
  842.  
  843.                         LocalLoudness = Loudness;
  844.                         do
  845.                             {
  846.                                 /* Loudness could be as high as 64, and the buffers have */
  847.                                 /* -16384..16383, which, added together, is -32768..32767 */
  848.                                 /* so we need to divide by 64 (shift left by 6) */
  849.                                 *(BufferAddress++) = (short)(
  850.                                     (((long)*(WA1Shadow++) + (long)*(WA2Shadow++)) * LocalLoudness)
  851.                                     >> 6) /*+ (short)0x8000*/;
  852.                                 number -= 1;
  853.                             } while (number > 0);
  854.                     }
  855.             }
  856.  
  857.         buf_index += BytesGenerated; /* account for added bytes */
  858.     }
  859.  
  860.  
  861. /* the actual functions for single-channel resampling */
  862.  
  863.  
  864. #if !USE_ASSEMBLY_CODE
  865. void            SampleAliased8(struct audio_channel* ch, short* Buffer, short Count)
  866.     {
  867.         long                Pointer;
  868.         long                FixLength;
  869.         char*                SampleData;
  870.         long                Step;
  871.         long                LoopLength;
  872.         short                Volume;
  873.  
  874.         if (ch->mode != DO_NOTHING)
  875.             {
  876.                 Pointer = ch->pointer;
  877.                 FixLength = ch->samp->fix_length;
  878.                 SampleData = ch->samp->start;
  879.                 Step = ch->step;
  880.                 LoopLength = ch->samp->fix_rp_length;
  881.                 Volume = CONSTRAIN(ch->volume,MIN_VOLUME,MAX_VOLUME) - MIN_VOLUME;
  882.              LoopPoint:
  883.                 if (Pointer >= FixLength)
  884.                     {
  885.                         /* is there a replay ? */
  886.                         if (!ch->samp->rp_start)
  887.                             {
  888.                                 ch->mode = DO_NOTHING;
  889.                                 goto OutPoint;
  890.                             }
  891.                         ch->mode = REPLAY;
  892.                         Pointer -= LoopLength;
  893.                         goto LoopPoint;
  894.                     }
  895.                 *(Buffer++) += (Volume * SampleData[fix_to_int(Pointer)]) >> 6;
  896.                 Pointer += Step;
  897.                 Count -= 1;
  898.                 if (Count > 0)
  899.                     {
  900.                         goto LoopPoint;
  901.                     }
  902.              OutPoint:
  903.                 ch->pointer = Pointer;
  904.             }
  905.     }
  906. #else
  907. void            SampleAliased8(struct audio_channel* ch, short* Buffer, short Count)
  908.     {
  909.         #define Pointer    D0
  910.         #define Step    D1
  911.         #define FixLength    D2
  912.         #define LocalCount    D3
  913.         #define Temp    D4
  914.         #define Temp2    D5
  915.  
  916.         #define SampleData    A0
  917.         #define VolumeMap    A1
  918.         #define Channel    A2
  919.         #define SampPtr    A3
  920.         #define LocalBuffer    A4
  921.  
  922.         asm
  923.             {
  924.                 movem.l            D3-D5/A2-A4,-(A7)
  925.  
  926.                 /* loading global variables & parameters:    Must NOT disturb A5 and A6 here */
  927.                 move.l            ch,Channel
  928.                 move.w            Count,LocalCount
  929.                 move.l            OFFSET(struct audio_channel,volume)(Channel),Temp    ;got volume
  930.                 cmp.l                #MIN_VOLUME,Temp
  931.                 bge.s                @8
  932.                 moveq.l            #0,Temp    ;if volume < 0, constrain it to 0
  933.         @8: cmp.l                #MAX_VOLUME,Temp
  934.                 bmi.s                @7
  935.                 moveq.l            #MAX_VOLUME,Temp    ;if volume > max volume, constain it to max
  936.         @7:
  937. #if 0 != MIN_VOLUME
  938.                 ;this bit is untested, but I think it will work.    Don't see why
  939.                 ;MIN_VOLUME would ever be != 0, though
  940.                 add.l                #(MIN_VOLUME * 256 * sizeof(short)),Temp    ;table starts at 0, so add this in
  941. #endif
  942.                 moveq                #9,Temp2
  943.                 lsl.l                Temp2,Temp    ;multiplied by 256*sizeof(short) to obtain offset
  944.                 move.l            SubVolumeTable,VolumeMap    ;get base address
  945.                 add.l                Temp,VolumeMap    ;add offset
  946.                 move.l            Buffer,LocalBuffer
  947.                 subq.w            #1,LocalCount
  948.                 /* loading channel things */
  949.                 move.l            OFFSET(struct audio_channel,pointer)(Channel),Pointer
  950.                 move.l            OFFSET(struct audio_channel,step)(Channel),Step
  951.                 /* loading sample things */
  952.                 move.l            OFFSET(struct audio_channel,samp)(Channel),SampPtr
  953.                 move.l            OFFSET(struct sample_info,fix_length)(SampPtr),FixLength
  954.                 move.l            OFFSET(struct sample_info,start)(SampPtr),SampleData
  955.                 /* clearing high bits of certain registers */
  956.  
  957.                 cmp.l                #DO_NOTHING,OFFSET(struct audio_channel,mode)(Channel)
  958.                 beq.s                @OutPoint
  959.  
  960.         @3: cmp.l                Pointer,FixLength
  961.                 bhi.s                @1
  962.                 tst.l                OFFSET(struct sample_info,rp_start)(SampPtr)
  963.                 bne.s                @2
  964.                 move.l            #DO_NOTHING,OFFSET(struct audio_channel,mode)(Channel)
  965.                 bra.s                @OutPoint
  966.         @2: sub.l                OFFSET(struct sample_info,fix_rp_length)(SampPtr),Pointer
  967.                 move.l            #REPLAY,OFFSET(struct audio_channel,mode)(Channel)
  968.                 bra.s                @3
  969.  
  970.         @1:
  971.                 move.l            Pointer,Temp
  972.                 moveq                #ACCURACY,Temp2
  973.                 lsr.l                Temp2,Temp    ;now Temp is the data index
  974.                 moveq.l            #0,Temp2
  975.                 move.b            0(SampleData,Temp.L),Temp2    ;get byte
  976. #if __option(mc68020)
  977.                 move.w            0(VolumeMap,Temp2.L*2),Temp    ;getting volume corrected value
  978. #else
  979.                 lsl.l                #1,Temp2
  980.                 move.w            0(VolumeMap,Temp2.L),Temp
  981. #endif
  982.                 add.w                Temp,(LocalBuffer)+    ;adding data into temporary buffer
  983.  
  984.                 add.l                Step,Pointer    ;incrementing pointer
  985.  
  986.                 dbf                    LocalCount,@3
  987.  
  988.         @OutPoint:
  989.                 move.l            Pointer,OFFSET(struct audio_channel,pointer)(Channel)
  990.                 movem.l            (A7)+,D3-D5/A2-A4
  991.             }
  992.  
  993.         #undef Pointer
  994.         #undef Step
  995.         #undef FixLength
  996.         #undef LocalCount
  997.         #undef Temp
  998.         #undef Temp2
  999.  
  1000.         #undef SampleData
  1001.         #undef VolumeMap
  1002.         #undef Channel
  1003.         #undef SampPtr
  1004.         #undef LocalBuffer
  1005.     }
  1006. #endif
  1007.  
  1008.  
  1009. #if !USE_ASSEMBLY_CODE
  1010. void            SampleAntiAliased8(struct audio_channel* ch, short* Buffer, short Count)
  1011.     {
  1012.         long                            Pointer;
  1013.         long                            FixLength;
  1014.         char*                            SampleData;
  1015.         long                            Step;
  1016.         long                            LoopLength;
  1017.         short                            Volume;
  1018.         short                            LeftWeight;
  1019.         short                            RightWeight;
  1020.  
  1021.         if (ch->mode != DO_NOTHING)
  1022.             {
  1023.                 Pointer = ch->pointer;
  1024.                 FixLength = ch->samp->fix_length;
  1025.                 SampleData = ch->samp->start;
  1026.                 Step = ch->step;
  1027.                 LoopLength = ch->samp->fix_rp_length;
  1028.                 Volume = CONSTRAIN(ch->volume,MIN_VOLUME,MAX_VOLUME) - MIN_VOLUME;
  1029.              LoopPoint:
  1030.                 if (Pointer >= FixLength)
  1031.                     {
  1032.                         /* is there a replay ? */
  1033.                         if (!ch->samp->rp_start)
  1034.                             {
  1035.                                 ch->mode = DO_NOTHING;
  1036.                                 goto OutPoint;
  1037.                             }
  1038.                         ch->mode = REPLAY;
  1039.                         Pointer -= LoopLength;
  1040.                         goto LoopPoint;
  1041.                     }
  1042.                 RightWeight = Pointer & ((1 << ACCURACY) - 1);
  1043.                 LeftWeight = (1 << ACCURACY) - RightWeight;
  1044.                 *(Buffer++) +=
  1045.                     (Volume * ((LeftWeight * SampleData[fix_to_int(Pointer)])
  1046.                     + (RightWeight * SampleData[fix_to_int(Pointer) + 1])) >> (ACCURACY + 1 + 6));
  1047.                 Pointer += Step;
  1048.                 Count -= 1;
  1049.                 if (Count > 0)
  1050.                     {
  1051.                         goto LoopPoint;
  1052.                     }
  1053.              OutPoint:
  1054.                 ch->pointer = Pointer;
  1055.             }
  1056.     }
  1057. #else
  1058. void            SampleAntiAliased8(struct audio_channel* ch, short* Buffer, short Count)
  1059.     {
  1060.         #define Pointer    D0
  1061.         #define Mask    D1
  1062.         #define Step    D2
  1063.         #define FixLength    D3
  1064.         #define LocalCount    D4
  1065.         #define Temp    D5
  1066.         #define Temp2    D6
  1067.  
  1068.         #define SampleData    A0
  1069.         #define AliasMap    A1
  1070.         #define VolumeMap    A2
  1071.         #define Channel    A3
  1072.         #define SampPtr    A4
  1073.         #define LocalBuffer    A5
  1074.  
  1075.         asm
  1076.             {
  1077.                 movem.l            D3-D6/A2-A5,-(A7)
  1078.  
  1079.                 /* loading global variables & parameters:    Must NOT disturb A5 and A6 here */
  1080.                 move.l            AliasTable,AliasMap
  1081.                 move.l            ch,Channel
  1082.                 move.w            Count,LocalCount
  1083.                 move.l            OFFSET(struct audio_channel,volume)(Channel),Temp    ;got volume
  1084.                 cmp.l                #MIN_VOLUME,Temp
  1085.                 bge.s                @8
  1086.                 moveq.l            #0,Temp    ;if volume < 0, constrain it to 0
  1087.         @8: cmp.l                #MAX_VOLUME,Temp
  1088.                 bmi.s                @7
  1089.                 moveq.l            #MAX_VOLUME,Temp    ;if volume > max volume, constain it to max
  1090.         @7:
  1091. #if 0 != MIN_VOLUME
  1092.                 ;this bit is untested, but I think it will work.    Don't see why
  1093.                 ;MIN_VOLUME would ever be != 0, though
  1094.                 add.l                #(MIN_VOLUME * 256 * sizeof(short)),Temp    ;table starts at 0, so add this in
  1095. #endif
  1096.                 moveq                #9,Temp2
  1097.                 lsl.l                Temp2,Temp    ;multiplied by 256*sizeof(short) to obtain offset
  1098.                 move.l            SubVolumeTable,VolumeMap    ;get base address
  1099.                 add.l                Temp,VolumeMap    ;add offset
  1100.                 move.l            Buffer,LocalBuffer
  1101.                 subq.w            #1,LocalCount
  1102.                 /* loading channel things */
  1103.                 move.l            OFFSET(struct audio_channel,pointer)(Channel),Pointer
  1104.                 move.l            OFFSET(struct audio_channel,step)(Channel),Step
  1105.                 /* loading sample things */
  1106.                 move.l            OFFSET(struct audio_channel,samp)(Channel),SampPtr
  1107.                 move.l            OFFSET(struct sample_info,fix_length)(SampPtr),FixLength
  1108.                 move.l            OFFSET(struct sample_info,start)(SampPtr),SampleData
  1109.  
  1110.                 /* clearing high bits of certain registers */
  1111. #if __option(mc68020)
  1112.                 ;this is an invariant optimization which is only meaningful on the 68020, so
  1113.                 ;we don't need it if we are compiling for 68000
  1114.                 clr.l                Mask
  1115. #endif
  1116.  
  1117.                 cmp.l                #DO_NOTHING,OFFSET(struct audio_channel,mode)(Channel)
  1118.                 beq.s                @OutPoint
  1119.  
  1120.         @3: cmp.l                Pointer,FixLength
  1121.                 bhi.s                @1
  1122.                 tst.l                OFFSET(struct sample_info,rp_start)(SampPtr)
  1123.                 bne.s                @2
  1124.                 move.l            #DO_NOTHING,OFFSET(struct audio_channel,mode)(Channel)
  1125.                 bra.s                @OutPoint
  1126.         @2: sub.l                OFFSET(struct sample_info,fix_rp_length)(SampPtr),Pointer
  1127.                 move.l            #REPLAY,OFFSET(struct audio_channel,mode)(Channel)
  1128.                 bra.s                @3
  1129.  
  1130.         @1:
  1131.                 ;calculating anti-aliasing mask
  1132. #if !__option(mc68020)
  1133.                 moveq.l            #0,Mask    ;make sure to clear the high bits each time for 68000
  1134. #endif
  1135.                 move.w            Pointer,Mask    ;get lower 16 bits of pointer
  1136.                 and.w                #0x0f00,Mask    ;keep only upper 4 bits of fraction
  1137.                 ;this conveniently works out to leave 8 bits just below the accuracy
  1138.                 ;into which we can stuff bytes. */
  1139. #if ACCURACY != 12
  1140. #error "ACCURACY == 12 is hardwired!"
  1141. #endif
  1142.  
  1143.                 ;fetching data bytes
  1144.                 move.l            Pointer,Temp
  1145.                 moveq                #ACCURACY,Temp2
  1146.                 lsr.l                Temp2,Temp    ;now Temp is the data index
  1147.                 moveq.l            #0,Temp2
  1148.                 move.b            0(SampleData,Temp.L),Mask    ;or in left byte
  1149. #if __option(mc68020)
  1150.                 move.b            0(AliasMap,Mask.L*2),Temp2    ;got left product
  1151.                 move.b            1(SampleData,Temp.L),Mask    ;or in right byte
  1152.                 add.b                1(AliasMap,Mask.L*2),Temp2    ;added in right product
  1153.                 move.w            0(VolumeMap,Temp2.L*2),Temp    ;getting volume corrected value
  1154. #else
  1155.                 lsl.l                #1,Mask
  1156.                 move.b            0(AliasMap,Mask.L),Temp2    ;got left product
  1157.                 lsr.l                #1,Mask    ;must shift back, since we OR in a byte next
  1158.                 move.b            1(SampleData,Temp.L),Mask    ;or in right byte
  1159.                 lsl.l                #1,Mask
  1160.                 add.b                1(AliasMap,Mask.L),Temp2    ;added in right product
  1161.                 lsl.l                #1,Temp2
  1162.                 move.w            0(VolumeMap,Temp2.L),Temp    ;getting volume corrected value
  1163. #endif
  1164.                 add.w                Temp,(LocalBuffer)+    ;adding data into temporary buffer
  1165.  
  1166.                 add.l                Step,Pointer    ;incrementing pointer
  1167.  
  1168.                 dbf                    LocalCount,@3
  1169.  
  1170.         @OutPoint:
  1171.                 move.l            Pointer,OFFSET(struct audio_channel,pointer)(Channel)
  1172.                 movem.l            (A7)+,D3-D6/A2-A5
  1173.             }
  1174.  
  1175.         #undef Pointer
  1176.         #undef Mask
  1177.         #undef Step
  1178.         #undef FixLength
  1179.         #undef LocalCount
  1180.         #undef Temp
  1181.         #undef Temp2
  1182.  
  1183.         #undef SampleData
  1184.         #undef AliasMap
  1185.         #undef VolumeMap
  1186.         #undef Channel
  1187.         #undef SampPtr
  1188.         #undef LocalBuffer
  1189.     }
  1190. #endif
  1191.  
  1192.  
  1193. /* Same as SampleAliased8 except it doesn't divide out the volume */
  1194. void            SampleAliased16(struct audio_channel* ch, short* Buffer, short Count)
  1195.     {
  1196.         long                Pointer;
  1197.         long                FixLength;
  1198.         char*                SampleData;
  1199.         long                Step;
  1200.         long                LoopLength;
  1201.         short                Volume;
  1202.  
  1203.         if (ch->mode != DO_NOTHING)
  1204.             {
  1205.                 Pointer = ch->pointer;
  1206.                 FixLength = ch->samp->fix_length;
  1207.                 SampleData = ch->samp->start;
  1208.                 Step = ch->step;
  1209.                 LoopLength = ch->samp->fix_rp_length;
  1210.                 Volume = CONSTRAIN(ch->volume,MIN_VOLUME,MAX_VOLUME) - MIN_VOLUME;
  1211.              LoopPoint:
  1212.                 if (Pointer >= FixLength)
  1213.                     {
  1214.                         /* is there a replay ? */
  1215.                         if (!ch->samp->rp_start)
  1216.                             {
  1217.                                 ch->mode = DO_NOTHING;
  1218.                                 goto OutPoint;
  1219.                             }
  1220.                         ch->mode = REPLAY;
  1221.                         Pointer -= LoopLength;
  1222.                         goto LoopPoint;
  1223.                     }
  1224.                 /* placing result in buffer -- ranges between 64*-128 .. 64*128. */
  1225.                 /* that way we can add two channels to get 15 bits worth of stuff */
  1226.                 /* or 4 channels for 16 bits worth of stuff */
  1227.                 *(Buffer++) += Volume * SampleData[fix_to_int(Pointer)];
  1228.                 Pointer += Step;
  1229.                 Count -= 1;
  1230.                 if (Count > 0)
  1231.                     {
  1232.                         goto LoopPoint;
  1233.                     }
  1234.              OutPoint:
  1235.                 ch->pointer = Pointer;
  1236.             }
  1237.     }
  1238.  
  1239.  
  1240. /* Same as SampleAntiAliased8 except it doesn't divide out the volume */
  1241. void            SampleAntiAliased16(struct audio_channel* ch, short* Buffer, short Count)
  1242.     {
  1243.         long                            Pointer;
  1244.         long                            FixLength;
  1245.         char*                            SampleData;
  1246.         long                            Step;
  1247.         long                            LoopLength;
  1248.         short                            Volume;
  1249.         short                            LeftWeight;
  1250.         short                            RightWeight;
  1251.  
  1252.         if (ch->mode != DO_NOTHING)
  1253.             {
  1254.                 Pointer = ch->pointer;
  1255.                 FixLength = ch->samp->fix_length;
  1256.                 SampleData = ch->samp->start;
  1257.                 Step = ch->step;
  1258.                 LoopLength = ch->samp->fix_rp_length;
  1259.                 Volume = CONSTRAIN(ch->volume,MIN_VOLUME,MAX_VOLUME) - MIN_VOLUME;
  1260.              LoopPoint:
  1261.                 if (Pointer >= FixLength)
  1262.                     {
  1263.                         /* is there a replay ? */
  1264.                         if (!ch->samp->rp_start)
  1265.                             {
  1266.                                 ch->mode = DO_NOTHING;
  1267.                                 goto OutPoint;
  1268.                             }
  1269.                         ch->mode = REPLAY;
  1270.                         Pointer -= LoopLength;
  1271.                         goto LoopPoint;
  1272.                     }
  1273.                 RightWeight = Pointer & ((1 << ACCURACY) - 1);
  1274.                 LeftWeight = (1 << ACCURACY) - RightWeight;
  1275.                 /* placing result in buffer -- ranges between 64*-128 .. 64*128. */
  1276.                 /* that way we can add two channels to get 15 bits worth of stuff */
  1277.                 /* or 4 channels for 16 bits worth of stuff */
  1278.                 *(Buffer++) +=
  1279.                     (Volume * (((LeftWeight * SampleData[fix_to_int(Pointer)])
  1280.                     + (RightWeight * SampleData[fix_to_int(Pointer) + 1])) >> (ACCURACY + 1)));
  1281.                 Pointer += Step;
  1282.                 Count -= 1;
  1283.                 if (Count > 0)
  1284.                     {
  1285.                         goto LoopPoint;
  1286.                     }
  1287.              OutPoint:
  1288.                 ch->pointer = Pointer;
  1289.             }
  1290.     }
  1291.